#include <rtthread.h>
#include <pjsua-lib/pjsua.h>
#include <pthread.h>
#include <rtdbg.h>

#define THIS_FILE "APP"

#define SIP_DOMAIN "192.168.1.30"
#define SIP_USER "7002"
#define SIP_PASSWD "7002"

/* Callback called by the library upon receiving incoming call */
static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
                             pjsip_rx_data *rdata)
{
    pjsua_call_info ci;

    PJ_UNUSED_ARG(acc_id);
    PJ_UNUSED_ARG(rdata);

    pjsua_call_get_info(call_id, &ci);

    PJ_LOG(3, (THIS_FILE, "Incoming call from %.*s!!",
               (int)ci.remote_info.slen,
               ci.remote_info.ptr));

    /* Automatically answer incoming calls with 200/OK */
    pjsua_call_answer(call_id, 200, NULL, NULL);
}

/* Callback called by the library when call's state has changed */
static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
{
    pjsua_call_info ci;

    PJ_UNUSED_ARG(e);

    pjsua_call_get_info(call_id, &ci);
    PJ_LOG(3, (THIS_FILE, "Call %d state=%.*s", call_id,
               (int)ci.state_text.slen,
               ci.state_text.ptr));
}

/* Callback called by the library when call's media state has changed */
static void on_call_media_state(pjsua_call_id call_id)
{
    pjsua_call_info ci;

    pjsua_call_get_info(call_id, &ci);

    if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE)
    {
        // When media is active, connect call to sound device.
        pjsua_conf_connect(ci.conf_slot, 0);
        pjsua_conf_connect(0, ci.conf_slot);
    }
}

/* Display error and exit application */
static void error_exit(const char *title, pj_status_t status)
{
    pjsua_perror(THIS_FILE, title, status);
    pjsua_destroy();
}

/*
 * voip main
 *
 */
void *simple_pjsua(void *argv)
{
    pjsua_acc_id acc_id;
    pj_status_t status;

    struct netdev *netdev;
    netdev = netdev_get_by_name("e0");

    // Wait Link Up!
    while(netdev_is_link_up(netdev) == 0)
    {
        sleep(1);
    }

    /* Create pjsua first! */
    status = pjsua_create();
    if (status != PJ_SUCCESS)
    {
        error_exit("Error in pjsua_create()", status);
        pthread_exit(NULL);
    }

    /* Init pjsua */
    pjsua_config pjsua_cfg;
    pjsua_logging_config log_cfg;

    pjsua_config_default(&pjsua_cfg);
    pjsua_cfg.cb.on_incoming_call = &on_incoming_call;
    pjsua_cfg.cb.on_call_media_state = &on_call_media_state;
    pjsua_cfg.cb.on_call_state = &on_call_state;

    pjsua_logging_config_default(&log_cfg);
    log_cfg.console_level = 4;

    status = pjsua_init(&pjsua_cfg, &log_cfg, NULL);
    if (status != PJ_SUCCESS)
    {
        error_exit("Error in pjsua_init()", status);
        pthread_exit(NULL);
    }

    sleep(1);

    /* Add UDP transport. */
    pjsua_transport_config pjsua_transport_cfg;

    pjsua_transport_config_default(&pjsua_transport_cfg);
    pjsua_transport_cfg.port = 5060;
    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &pjsua_transport_cfg, NULL);
    if (status != PJ_SUCCESS)
    {
        error_exit("Error creating transport", status);
        pthread_exit(NULL);
    }

    /* Initialization is done, now start pjsua */
    status = pjsua_start();
    if (status != PJ_SUCCESS)
    {
        error_exit("Error starting pjsua", status);
        pthread_exit(NULL);
    }

    /* Register to SIP server by creating SIP account. */
    pjsua_acc_config pjsua_acc_cfg;

    pjsua_acc_config_default(&pjsua_acc_cfg);
    pjsua_acc_cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
    pjsua_acc_cfg.reg_uri = pj_str("sip:" SIP_DOMAIN);
    pjsua_acc_cfg.cred_count = 1;
    pjsua_acc_cfg.cred_info[0].realm = pj_str("*");
    pjsua_acc_cfg.cred_info[0].scheme = pj_str("digest");
    pjsua_acc_cfg.cred_info[0].username = pj_str(SIP_USER);
    pjsua_acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
    pjsua_acc_cfg.cred_info[0].data = pj_str(SIP_PASSWD);

    status = pjsua_acc_add(&pjsua_acc_cfg, PJ_TRUE, &acc_id);
    if (status != PJ_SUCCESS)
    {
        error_exit("Error adding account", status);
        pthread_exit(NULL);
    }

    pthread_exit(NULL);
    return NULL;
}


static int pjsip_init(void)
{
    // 使能PJSIP
    static pthread_t thread;
    pthread_attr_t attr;

    pthread_attr_init(&attr);
    attr.stacksize = (16 * 1024);
    pthread_create(&thread, &attr, simple_pjsua, NULL);

    return RT_EOK;
}

INIT_APP_EXPORT(pjsip_init);
